package com.dks.repository.impl.classHour;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.dks.enumeration.*;
import com.dks.exception.BaseException;
import com.dks.mapper.*;
import com.dks.models.QsClass;
import com.dks.models.classHour.ClassHourUseRecord;
import com.dks.models.student.*;
import com.dks.repository.IClassHourUseRepository;
import com.dks.result.ResultInfo;
import io.jsonwebtoken.lang.Collections;
import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * 课时包使用相关
 */
@Repository
public class ClassHourUseRepository implements IClassHourUseRepository {

    @Autowired
    private ClassHourUseRecordMapper classHourUseRecordMapper;
    @Autowired
    private UserClassHourPackageMapper userClassHourPackageMapper;
//    @Autowired
//    private QsClassMapper qsClassMapper;
    @Autowired
    private StudentClassMapper studentClassMapper;
    @Autowired
    private PositionWaitMapper positionWaitMapper;

    /***
     * 使用 => 约课
     * @author evan
     */
    @Override
    @Transactional
    public void useAppointClass(List<? extends QsClass> qsClassList, long userId, long studentId, long parentId, AppointmentType appointmentType) throws BaseException {
//        //1.班级查询
//        QsClass qsClass = qsClassMapper.select(qsClassId);
//        if (qsClass == null){
//            throw new BaseException(ResultInfo.ERR_CLASS_001);
//        }
//        //根据课程系列id查询从当前日期之后的所有班级
//        List<QsClassCapacityDto> qsClassCapacityDtoList = qsClassMapper.getCountBySeriesId(qsClass.getQsClassSeriesId(), qsClass.getLessonStartTime());
        //2.课时包查询
        List<UserClassHourPackage> userClassHourPackageList = getPackageByUserId(userId, ClassHourPackageType.NORMAL);
        if (Collections.isEmpty(userClassHourPackageList)){
            throw new BaseException(ResultInfo.ERR_CLASS_HOUR_PACKAGE_001);
        }
        //4.判断可用课时数是否够用
        if (availableClassHourCount(userClassHourPackageList) < neededClassHourCount(qsClassList)){
            throw new BaseException(ResultInfo.ERR_APPOINT_CLASS_002);
        }
        List<ClassHourPackageUseInfo> totalUseInfoList = new ArrayList<>();
        for (QsClass qsClass : qsClassList){
            //5.班级位置锁定
            StudentClass studentClass = classPositionLock(qsClass.getId(), userId, studentId, parentId, appointmentType);
            //6.扣除课时统计
            List<ClassHourPackageUseInfo> classHourPackageUseInfoList = frozenClassHour(qsClass.getPeriodBasic(), userClassHourPackageList);
            totalUseInfoList = count(totalUseInfoList, classHourPackageUseInfoList);
            //7.添加课时使用记录
            makeClassHourUseRecord(userId, studentClass.getId(), classHourPackageUseInfoList, 1);
        }
        //8.用户课时包修改
        frozenClassHour(totalUseInfoList, userId);
    }

    /***
     * 使用 => 等位
     * @author evan
     */
    @Override
    @Transactional
    public void useWaitClass(List<? extends QsClass> qsClassList, long userId, long studentId, long parentId) throws BaseException {
        //2.课时包查询
        List<UserClassHourPackage> userClassHourPackageList = getPackageByUserId(userId, ClassHourPackageType.NORMAL);
        if (Collections.isEmpty(userClassHourPackageList)){
            throw new BaseException(ResultInfo.ERR_CLASS_HOUR_PACKAGE_001);
        }
        //4.判断可用课时数是否够用
        int neededClassHourCount = neededClassHourCount(qsClassList);
        if (availableClassHourCount(userClassHourPackageList) < neededClassHourCount){
            throw new BaseException(ResultInfo.ERR_APPOINT_CLASS_002);
        }
        //5.等位锁定
        PositionWait positionWait = positionWaitLock(qsClassList.get(0).getQsClassSeriesId(), userId, studentId, parentId);
        //6.扣除课时统计
        List<ClassHourPackageUseInfo> classHourPackageUseInfoList = frozenClassHour(neededClassHourCount, userClassHourPackageList);
        List<ClassHourPackageUseInfo> totalUseInfoList = new ArrayList<>();
        totalUseInfoList = count(totalUseInfoList, classHourPackageUseInfoList);
        //7.添加课时使用记录
        makeClassHourUseRecord(userId, positionWait.getId(), classHourPackageUseInfoList, 0);
        //8.用户课时包修改
        frozenClassHour(totalUseInfoList, userId);
    }

    /***
     * 取消使用 => 停课等 解冻课时
     * @author evan
     */
    @Override
    @Transactional
    public void useCancel(List<StudentClass> studentClassList, long userId) throws BaseException {
        if (studentClassList == null){
            return;
        }
        //1.查询使用记录
        List<ClassHourPackageUseInfo> useInfoList = new ArrayList<>();
        for (StudentClass studentClass : studentClassList){
            List<ClassHourUseRecord> classHourUseRecordList = classHourUseRecordMapper.getByStudentClassId(studentClass.getId());
            if (Collections.isEmpty(classHourUseRecordList)){
                continue;
            }
            //2.使用记录统计
            for (ClassHourUseRecord classHourUseRecord : classHourUseRecordList){
                useInfoList = count(useInfoList, new ClassHourPackageUseInfo(classHourUseRecord.getStudentClassId(), classHourUseRecord.getClassHourCount()));
            }
            //3.修改学生班级表
            int i = studentClassMapper.remove(studentClass.getId());
            if (i <= 0){
                throw new BaseException(ResultInfo.ERR_STUDENT_005);
            }
        }
        //3.用户课时包修改 => 解冻课时
        unFrozenClassHour(useInfoList, userId);

    }

    /***
     * 取消使用 => 取消等位
     * @author evan
     */
    @Override
    @Transactional
    public void waitCancel(List<PositionWait> positionWaitList, long userId, Integer fixedWaitCancelLimit) throws BaseException {
        if (positionWaitList == null){
            return;
        }
        //1.查询使用记录
        List<ClassHourPackageUseInfo> useInfoList = new ArrayList<>();
        for (PositionWait positionWait : positionWaitList){
            List<ClassHourUseRecord> classHourUseRecordList = classHourUseRecordMapper.getByPositionWaitId(positionWait.getId());
            if (Collections.isEmpty(classHourUseRecordList)){
                continue;
            }
            //2.使用记录统计
            for (ClassHourUseRecord classHourUseRecord : classHourUseRecordList){
                useInfoList = count(useInfoList, new ClassHourPackageUseInfo(classHourUseRecord.getStudentClassId(), classHourUseRecord.getClassHourCount()));
            }
            //3.修改等位表
            int i = positionWaitMapper.remove(positionWait.getId());
            if (i <= 0){
                throw new BaseException(ResultInfo.ERR_STUDENT_005);
            }
        }
        //4.用户课时包修改 => 解冻课时
        unFrozenClassHour(useInfoList, userId);

    }

    /***
     * 查询 根据课程查询
     * @author evan
     */
    public List<ClassHourPackage> select(long qsClassId){
        return null;
    }


    /***
     * 获取用户可用的课时包
     * @author evan
     */
    public List<UserClassHourPackage> getPackageByUserId(long userId, ClassHourPackageType classHourPackageType){
        //查询用户可用的课时包
        List<UserClassHourPackage> availablePackageList = userClassHourPackageMapper.getAvailableList(userId, classHourPackageType.name(),"lately");
        if (Collections.isEmpty(availablePackageList)){
            return null;
        }
        return availablePackageList;
    }

    /***
     * 用户课时包排序 剩余有效期最短的课时包 如果相同 按购买时间最早
     * @author evan
     */
    public List<UserClassHourPackage> sort(List<UserClassHourPackage> userClassHourPackageList){
        if (Collections.isEmpty(userClassHourPackageList)){
            return null;
        }
        userClassHourPackageList.sort((userClassHourPackage1, userClassHourPackage2)->{
            if (userClassHourPackage1.getExpireTime().isBefore(userClassHourPackage2.getExpireTime())){
                return 1;
            }else if (userClassHourPackage1.getExpireTime().isAfter(userClassHourPackage2.getExpireTime())){
                return -1;
            }else{
                if (userClassHourPackage1.getGmtCreateTime().isBefore(userClassHourPackage2.getGmtCreateTime())){
                    return 1;
                }else if (userClassHourPackage1.getGmtCreateTime().isAfter(userClassHourPackage2.getGmtCreateTime())){
                    return -1;
                }else{
                    return 0;
                }
            }
        });
        return userClassHourPackageList;
    }

    /***
     * 可用课时数统计
     * @author evan
     */
    public int availableClassHourCount(List<UserClassHourPackage> userClassHourPackageList){
        return userClassHourPackageList.stream().mapToInt(UserClassHourPackage::getAvailableClassHourCount).sum();
    }
    /***
     * 需要课时数统计
     * @author evan
     */
    public int neededClassHourCount(List<? extends QsClass> qsClassList){
        return qsClassList.stream().mapToInt(QsClass::getPeriodBasic).sum();
    }

    /***
     * 课时包冻结课时
     * @author evan
     */
    public List<ClassHourPackageUseInfo> frozenClassHour(int classHour, List<UserClassHourPackage> userClassHourPackageList) throws BaseException {
        List<ClassHourPackageUseInfo> useInfoList = new ArrayList<>();
        for (UserClassHourPackage userClassHourPackage : userClassHourPackageList){
            if (userClassHourPackage.getAvailableClassHourCount() > 0){
                if (classHour > userClassHourPackage.getAvailableClassHourCount()){
                    userClassHourPackage.setAvailableClassHourCount(0);
                    userClassHourPackage.setFrozenClassHourCount(userClassHourPackage.getAvailableClassHourCount() + userClassHourPackage.getFrozenClassHourCount());
                    classHour -= userClassHourPackage.getAvailableClassHourCount();
                    //当前课时包不够用
                    useInfoList.add(new ClassHourPackageUseInfo(userClassHourPackage.getId(), userClassHourPackage.getAvailableClassHourCount()));
                }else{
                    userClassHourPackage.setAvailableClassHourCount(userClassHourPackage.getAvailableClassHourCount() - classHour);
                    userClassHourPackage.setFrozenClassHourCount(userClassHourPackage.getAvailableClassHourCount() + classHour);
                    useInfoList.add(new ClassHourPackageUseInfo(userClassHourPackage.getId(), classHour));
                    return useInfoList;
                }
            }
        }
        throw new BaseException(ResultInfo.ERR_APPOINT_CLASS_001);
    }

    /***
     * 班级位置锁定
     * @author evan
     */
    public StudentClass classPositionLock(long qsClassId, long userId, long studentId, long parentId, AppointmentType appointmentType) throws BaseException {
        StudentClass studentClass = new StudentClass();
        studentClass.setParentId(parentId);
        studentClass.setStudentId(studentId);
        studentClass.setQsClassId(qsClassId);
        studentClass.setClassAttendStatus(ClassAttendStatus.NOT_SIGN_IN.name());
        studentClass.setAppointmentType(appointmentType.name());
        studentClass.setCreateUserId(userId);
        int i = studentClassMapper.insert(studentClass);
        if (i <= 0){
            throw new BaseException(ResultInfo.ERR_APPOINT_CLASS_001);
        }
        return studentClass;
    }

    /***
     * 等位锁定
     * @author evan
     */
    public PositionWait positionWaitLock(long qsClassSeriesId, long userId, long studentId, long parentId) throws BaseException {
        PositionWait positionWait = new PositionWait();
        positionWait.setStudentId(studentId);
        positionWait.setParentId(parentId);
        positionWait.setQsClassSeriesId(qsClassSeriesId);
        positionWait.setCreateUserId(userId);
        int i = positionWaitMapper.insert(positionWait);
        if (i <= 0){
            throw new BaseException(ResultInfo.ERR_APPOINT_CLASS_001);
        }
        return positionWait;
    }

    /***
     * 课时使用记录
     * @param type 类型：0.等位 1.约课
     * @author evan
     * 约课：按照每节课 存记录（一个课可能使用多个课时包所以可能有多条数据）
     * 等位：按照等位表 存记录（每节课等位失败，修改等位表的冻结课时）
     */
    public void makeClassHourUseRecord(long userId, long positionId, List<ClassHourPackageUseInfo> UseInfoList, int type){
        for (ClassHourPackageUseInfo userInfo: UseInfoList){
            ClassHourUseRecord classHourUseRecord = new ClassHourUseRecord();
            if (type == 0){ //等位
                classHourUseRecord.setPositionWaitId(positionId);
            }else{ //约课
                classHourUseRecord.setStudentClassId(positionId);
            }
            classHourUseRecord.setUserClassHourPackageId(userInfo.getId());
            classHourUseRecord.setClassHourCount(userInfo.getClasshour());
            classHourUseRecord.setType(type);
            classHourUseRecord.setCreateUserId(userId);
            classHourUseRecordMapper.insert(classHourUseRecord);
        }
    }

    /***
     * 使用课时统计
     * @author evan
     */
    public List<ClassHourPackageUseInfo> count(List<ClassHourPackageUseInfo> list1, List<ClassHourPackageUseInfo> list2){
        if (Collections.isEmpty(list1)){
            return list2;
        }
        for (ClassHourPackageUseInfo c1 : list1){
            for (ClassHourPackageUseInfo c2 : list2){
                if (c1.getId() == c2.getId()){
                    c1.setClasshour(c1.getClasshour() + c2.getClasshour());
                }
            }
        }
        return list1;
    }

    /***
     * 使用课时统计
     * @author evan
     */
    public List<ClassHourPackageUseInfo> count(List<ClassHourPackageUseInfo> list, ClassHourPackageUseInfo c){
        if (Collections.isEmpty(list)){
            list.add(c);
            return list;
        }
        for (ClassHourPackageUseInfo c1 : list){
            if (c1.getId() == c.getId()){
                c1.setClasshour(c1.getClasshour() + c.getClasshour());
            }
        }
        return list;
    }

    /***
     * 冻结课时
     * @author evan
     */
    public void frozenClassHour(List<ClassHourPackageUseInfo> useInfoList, long userId) throws BaseException {
        for (ClassHourPackageUseInfo useInfo : useInfoList){
            int i = userClassHourPackageMapper.frozenClassHour(useInfo.getId(), useInfo.getClasshour(), userId);
            if (i <= 0){
                throw new BaseException(ResultInfo.ERR_APPOINT_CLASS_001);
            }
        }
    }

    /***
     * 解冻课时
     * @author evan
     */
    public void unFrozenClassHour(List<ClassHourPackageUseInfo> useInfoList, long userId) throws BaseException {
        for (ClassHourPackageUseInfo useInfo : useInfoList) {
            int i = userClassHourPackageMapper.unFrozenClassHour(useInfo.getId(), useInfo.getClasshour(), userId);
            if (i <= 0) {
                throw new BaseException(ResultInfo.ERR_APPOINT_CLASS_001);
            }
        }
    }

}

/***
 * 课时包使用信息
 */
@Data
@AllArgsConstructor
class ClassHourPackageUseInfo{
    //用户课时包id
    private long id;
    //课时数
    private int classhour;
}
